package com.segersten.kalaha

import grails.converters.*
import java.util.logging.Logger
import com.segersten.kalaha.domain.EventType

class GameController {
	
	private static Logger LOG = Logger.getLogger(GameController.class.getCanonicalName());
	
	def facebookKeys
	def kalahasettings
	
	def index = { render(text:"Welcome to GameController")}

	/** gsp view **/
    def game  = { 
    	BoardSessionCache c = new BoardSessionCache()
    	
    	BoardSession bs = c.get(params.gameSessionId)
		
		PlayerCache pc = new PlayerCache()
		Player p = pc.getBySessionId(params.clientSessionId)
		def playerId=null
		if (p!=null) {
			playerId = p.userId
		}
		
		if (bs==null) {
			FinishedGame fg = FinishedGame.find("select from FinishedGame as f where f.sessionId = :id", [id:params.gameSessionId])
			if (fg!=null) {
				bs = new BoardSession(
					sessionId:fg.sessionId,
					gameType:GameType.KALAHA,
					player1:new Player(userId:fg.getPlayer1(),name:fg.getPlayer1()),
					player2:new Player(userId:fg.getPlayer2(),name:fg.getPlayer2())
				)
			}
		}
		
		int score1 = 0;
		PlayerScoreWeek ps1 = SessionTicket.find("SELECT FROM PlayerScoreWeek sc WHERE sc.userId = :id", [id:bs.player1.userId])
		if (ps1 != null) {
			score1 = ps1.score
		}
		int score2 = 0;
		PlayerScoreWeek ps2 = SessionTicket.find("SELECT FROM PlayerScoreWeek sc WHERE sc.userId = :id", [id:bs.player2.userId])
		if (ps2 != null) {
			score2 = ps2.score
		}
		
    	[bsId:params.gameSessionId, 
		 bs:bs, itemCount:c.stats().itemCount,
		 clientSessionId:params.clientSessionId,
		 playerId:playerId, score1:score1, score2:score2]
    }
	
	def lookupFinishedBoardSession = {
		FinishedGame fg = FinishedGame.find("select from FinishedGame as f where f.sessionId = :id", [id:params.gameSessionId])
		
		if (fg==null) {
			response.status = 404
			render(text:"Not found - ${params.gameSessionId}")
			return
		} else {
			response.setHeader("Cache-Control","max-age=3600")
			render(contentType:"text/json") {
				sessionId = params.gameSessionId
				player1 = [userId:fg.player1, name:fg.player1Name]
				player2 = [userId:fg.player2, name:fg.player2Name]
				gameType = fg.gameType
				nextActor = Actor.NONE.name()
				model = calculateKalahaModel(fg.endState)
				lastUpdated = fg.finishedTime
				round = -1
				state = fg.getFinishedReason()
				winner = fg.getWinner()
				player1score = fg.player1Points
				player2score = fg.player2Points
				timestamp = new Date().getTime();
			}
			return
		}
	}
    
    def lookupBoardSession = {
    	BoardSessionCache c = new BoardSessionCache()
    	
    	BoardSession boardSession = c.get(params.gameSessionId)
    	
		if (!boardSession) {
			
			FinishedGame fg = FinishedGame.find("select from FinishedGame as f where f.sessionId = :id", [id:params.gameSessionId])
			
			if (fg==null) {				
				response.status = 404
				render(text:"Not found")
				return
			} else {
				response.setHeader("Location", "http://${facebookKeys.callbackDomain}/finishedgames/${params.gameSessionId}")
				response.status = 301
				render(text:"")
				return 
			}
		} else {
			LOG.info("Found log")
		}
	    render(contentType:"text/json") { 
										  sessionId = params.gameSessionId
										  player1 = [name:boardSession.player1.name, userId:boardSession.player1.userId]
										  player2 = [name:boardSession.player2.name, userId:boardSession.player2.userId]
										  gameType = boardSession.gameType.name()
										  nextActor = boardSession.nextActor.name()
										  model = boardSession.board.buckets
										  lastUpdated = boardSession.lastUpdated.time
										  lastUpdated2 = boardSession.lastUpdated
										  round = boardSession.getLastEvent().round
										  roundDuration = boardSession.roundDuration
										  timestamp = new Date().getTime();
									}
		
    }
    

    def lookupEvents = {
    	BoardSessionCache c = new BoardSessionCache()
    	BoardSession bs = c.get(params.gameSessionId)
		
		if (!bs) {
			response.status = 404
			render(text:"Not found")
			return
		}
    	
   		render(contentType:"text/json") {
		events = array {
			for(e in bs.events) {
				event(type:e.type.name(), 
					  arg:e.arg,
					  time:e.created.time)
				}
			}	
		}
    }
	
	def lookupRoundEvent  = {
		BoardSessionCache c = new BoardSessionCache()
		BoardSession bs = c.get(params.gameSessionId)
		
		if (!bs) {
			response.status = 404
			render(text:"Not found")
			return
		}
		
		def event = bs.events[Integer.parseInt(params.round)]
		if (!event) {
			response.status = 404
			render(text:"Not found")
			return
		}
		
		render(contentType:"text/json") {
			event(type:e.type.name(),
					arg:e.arg,
					time:e.created.time)
			}
	}
    
    def addPlayerEvent = {
    	PlayerCache pc = new PlayerCache()
    	Player p = pc.getBySessionId(params.clientSessionId)
    	if (!p) {
			response.status = 401
			render(text:"Unauthorized action")
    		return // error - not allowed to append
    	}
    	
    	if (!params.arg) {
			response.status = 402
			render(text:"error - no event argument")
    		return // error - not allowed to append
    	}
    	
    	BoardSessionCache c = new BoardSessionCache()
    	BoardSession bs = c.get(params.gameSessionId)
    	
    	if (!bs) {
			response.status = 404
			render(text:"error - no game session found")
    		return // error - not allowed to append
    	}
		
		def eventType
		if (params.arg=="timeout") {
			if (bs.nextActor == Actor.PLAYER_1) {
				eventType = EventType.PLAYER_1_TIMEOUT
			} else if (bs.nextActor == Actor.PLAYER_2) {
				eventType = EventType.PLAYER_2_TIMEOUT
			}
		} else if (bs.player1.userId == p.userId) {
			eventType = EventType.PLAYER_1_ACTION
		} else if (bs.player2.userId == p.userId) {
			eventType = EventType.PLAYER_2_ACTION
		} else {
			response.status = 400
			render(text:"error - unknown event type")
			return // error - not allowed to append
    	}
		
		if (params.discrepancy!=null) {
			LOG.info("discrepancy = " + params.discrepancy)
		}
		
		if (params.arg!="timeout" && bs.getLastUpdated().before(new Date(new Date().getTime()-Integer.parseInt(kalahasettings.roundDuration)*1000L))) {
			// time out, will be removed by cron job shortly
			response.status = 402
			render(text:"error - game has been timed out")
			return
		}
    	
    	def updateCache = bs.addEvent(eventType, params.arg)
    	if (updateCache) {
			c.put(bs)
    	}
    	
		if(params.reload!=null && params.reload=="true") {
			redirect(action:game, params:params)  // this will change
		} else {
			response.status = 200
			render(text:"OK")
		}
    }
    	
	
	def calculateKalahaModel = { String model ->
		Logger LOG = Logger.getLogger(getClass().getCanonicalName());
		//LOG.info("calculateKalahaModel " + model);
		String m = model.substring(1, model.length()-1)
		//LOG.info("calculateKalahaModel " + m);
		List<Integer> buckets = new ArrayList<Integer>(14)
		String []tokens = m.split(",")
		tokens.each { token ->
			buckets.add(Integer.parseInt(token))
		 }
		//LOG.info("calculateKalahaModel " + buckets);
		return buckets
	}
    
}
